import L from "leaflet"

L.WindFeatherLayer = L.Layer.extend({
	includes: L.Mixin.Events,

	options: {
		windDataUV: [],
		zIndex: 20, //图层index
		scale: 0.22,
		startLon: 0,
		endLon: 360,
		startLat: 90,
		endLat: -90,
	},

	SetData: function (windDataUV) {
		let self = this;
		self.options.windDataUV = windDataUV
		self._reset();
	},
	_reset: function () {
		let container = this._container
		let canvas = this._canvas
		let size = this._map.getSize()
		let lt = this._map.containerPointToLayerPoint([0, 0]);

		L.DomUtil.setPosition(container, lt);

		container.style.width = size.x + 'px';
		container.style.height = size.y + 'px';

		canvas.width = size.x;
		canvas.height = size.y;
		canvas.style.width = size.x + 'px';
		canvas.style.height = size.y + 'px';

		this._draw(true);
	},
	_draw: function () {
		let self = this, canvas = this._canvas, map = this._map;
		if (self.options.windDataUV.length <= 0) {
			return;
		}
		let startLon = self.options.startLon;
		let startLat = self.options.startLat;
		let endLon = self.options.endLon;
		let endLat = self.options.endLat;

		if (L.Browser.canvas && map) {
			let ctx = canvas.getContext('2d');
			ctx.clearRect(0, 0, canvas.width, canvas.height);
			self.id = self._makeid();
			let id = self.id;
			this.currentzoom = map.getZoom();
			this.currentbounds = map.getBounds();
			this.leftup = this.currentbounds.getNorthWest();
			this.rightdown = this.currentbounds.getSouthEast();
			this.range = this._getRange(this.leftup, this.rightdown, this.currentzoom);

			let dataCell = (startLat - endLat) / self.options.windDataUV.length
			let z = self.currentzoom, zr = Math.pow(2, z);
			for (let i = this.range.up; i <= this.range.down; i++) {
				for (let j = this.range.left; j <= this.range.right; j++) {
					let zheng = Math.floor(j / zr);
					let yu = j % zr;
					if (yu < 0) {
						yu = yu + zr;
					}
					let row = i;
					let col = yu;
					let cellInterval = 2 * Math.PI / (256 * Math.pow(2, z));
					let firstX = col * cellInterval * 256 - Math.PI + cellInterval / 2;
					let firstY = Math.PI - (row * cellInterval * 256) - cellInterval / 2;
					let interval = 64;
					for (let h = 0; h < 256 / interval; h++) {
						for (let w = 0; w < 256 / interval; w++) {
							let lonlat = self._getLonlat(firstX, firstY, cellInterval, w * interval, h * interval);
							let lon = lonlat.lon;
							let lat = lonlat.lat;
							let querylng = lon;
							querylng = querylng % 360;
							if (querylng < 0) {
								querylng = querylng + 360;
							}
							if (lat > startLat && lat < endLat && querylng < startLon && querylng > endLon) {
								continue
							}
							if (!self.options.windDataUV[Math.floor((startLat - lat) / dataCell)]) {
								continue
							}
							if (!self.options.windDataUV[Math.floor((startLat - lat) / dataCell)][Math.floor((querylng - startLon) / dataCell)]) {
								continue
							}
							let uv = self.options.windDataUV[Math.floor((startLat - lat) / dataCell)][Math.floor((querylng - startLon) / dataCell)];
							if (!uv) { continue }
							let u = uv.u, v = uv.v;
							if (u === 0 && v === 0) {
								continue
							}
							lon = lonlat.lon + 360 * zheng;
							let screenpoint = map.latLngToContainerPoint(L.latLng(lat, lon));

							let uvInfo = self._computeUV(u, v);
							let value = uvInfo.value;
							let angle = uvInfo.angle;
							let level = self._chooseWindLevel(value);
							let color = self._setcolor(value);
							color.a = 1;
							self._drawIcon(ctx, screenpoint.x, screenpoint.y, self.options.scale, angle, color, level, id);
						}
					}
				}
			}
		}
	},
	_drawIcon: function (context, x, y, scale, angle, color, windlevel, id) {
		let self = this;
		let image = new Image();
		// image.src = require(`./wind/${windlevel}.png`);
		image.src = new URL(`./wind/${windlevel}.png`, import.meta.url).href
		image.onload = function () {
			if (id !== self.id) { return; }
			context.save();
			let w = image.width * scale;
			let h = image.height * scale;
			context.translate(x + w / 2, y + h / 2);
			context.rotate(angle * Math.PI / 180);
			context.drawImage(image, -(w / 2), -(h / 2), w, h);
			let li = Math.sqrt(w * w + h * h); //斜边
			context.restore();
			let dataL = context.getImageData(x + w / 2 - li / 2, y + h / 2 - li / 2, li, li);
			for (let i = 0; i < dataL.data.length; i += 4) { //逐像素修改颜色透明度
				if (dataL.data[i] === 0 && dataL.data[i + 1] === 0 && dataL.data[i + 2] === 0 && dataL.data[i + 3] === 0) {
					continue;
				}
				dataL.data[i] = color.r + dataL.data[i] - 255;
				dataL.data[i + 1] = color.g + dataL.data[i + 1] - 255;
				dataL.data[i + 2] = color.b + dataL.data[i + 2];
				dataL.data[i + 3] = dataL.data[i + 3]; //体现阴影效果
			}
			context.putImageData(dataL, x + w / 2 - li / 2, y + h / 2 - li / 2);
		};

	},
	_clearCanvas: function () {
		let canvas = this._canvas;
		try {
			let ctx = canvas.getContext('2d');
			ctx.clearRect(0, 0, canvas.width, canvas.height);
		} catch (e) {
			console.log(e);
		}
	},

	/*------------------------------------ 外置函数 ------------------------------------------*/

	setzIndex: function (zIndex) {
		this._container.style.zIndex = zIndex;
	},

	/*------------------------------------ 事件 ------------------------------------------*/

	initialize: function (options) {
		L.setOptions(this, options);
		this.currentbounds = null;
		this.currentzoom = null;
	},
	onAdd: function (map) {
		this._map = map;
		if (!this._container) {
			this._initCanvas();
		}
		map._panes.overlayPane.appendChild(this._container);
		map.on('zoomstart', this._clearCanvas, this);
		map.on('moveend', this._reset, this);
		if (map.options.zoomAnimation && L.Browser.any3d) {
			map.on('zoomanim', this._animateZoom, this);
		}
		this._reset();
	},
	onRemove: function (map) {
		map.getPanes().overlayPane.removeChild(this._container);
		map.off('zoomstart', this._clearCanvas, this);
		map.off('moveend', this._reset, this);
		if (map.options.zoomAnimation) {
			map.off('zoomanim', this._animateZoom, this);
		}
	},
	addTo: function (map) {
		map.addLayer(this);
		return this;
	},
	bringToBack: function () {
		let pane = this._map._panes.overlayPane;
		if (this._canvas) {
			pane.insertBefore(this._canvas, pane.firstChild);
		}
		return this;
	},
	_initCanvas: function () {
		this._container = L.DomUtil.create('div', 'leaflet-image-layer');
		this._canvas = L.DomUtil.create('canvas', '');
		this._canvas.style.pointerEvents = "none";
		this.setzIndex(this.options.zIndex);

		if (this._map.options.zoomAnimation && L.Browser.any3d) {
			L.DomUtil.addClass(this._canvas, 'leaflet-zoom-animated');
		} else {
			L.DomUtil.addClass(this._canvas, 'leaflet-zoom-hide');
		}

		this._container.appendChild(this._canvas);

		L.extend(this._canvas, {
			onselectstart: L.Util.falseFn,
			onmousemove: L.Util.falseFn,
			onload: L.bind(this._onCanvasLoad, this)
		});
	},
	_animateZoom: function (e) {
		let map = this._map,
			container = this._container,
			canvas = this._canvas,
			scale = map.getZoomScale(e.zoom),
			nw = map.containerPointToLatLng([0, 0]),
			se = map.containerPointToLatLng([canvas.width, canvas.height]),
			topLeft = map._latLngToNewLayerPoint(nw, e.zoom, e.center),
			size = map._latLngToNewLayerPoint(se, e.zoom, e.center)._subtract(topLeft),
			origin = topLeft._add(size._multiplyBy(1 / 2 * (1 - 1 / scale)));
	},
	_onCanvasLoad: function () {
		this.fire('load');
	},

	/*------------------------------------ 工具函数 ------------------------------------------*/

	/**角度修正 */
	_correctAngle: function (angle) {
		angle = angle / Math.PI * 180.0 + 90;
		if (angle < 0) {
			angle = angle + 360;
		}
		angle = 360 - angle;
		return angle;
	},
	/**风力选择 */
	_chooseWindLevel: function (speed) {
		let level;
		if (speed >= 0 && speed <= 2) {
			level = 1;
		} else if (speed > 2 && speed <= 4) {
			level = 2;
		} else if (speed > 4 && speed <= 6) {
			level = 3;
		} else if (speed > 6 && speed <= 8) {
			level = 4;
		} else if (speed > 8 && speed <= 10) {
			level = 5;
		} else if (speed > 10 && speed <= 12) {
			level = 6;
		} else if (speed > 12 && speed <= 14) {
			level = 7;
		} else if (speed > 14 && speed <= 16) {
			level = 8;
		} else if (speed > 16 && speed <= 18) {
			level = 9;
		} else if (speed > 18 && speed <= 20) {
			level = 10;
		} else if (speed > 20 && speed <= 24) {
			level = 11;
		} else if (speed > 24 && speed <= 28) {
			level = 12;
		} else if (speed > 28 && speed <= 32) {
			level = 13;
		} else if (speed > 32 && speed <= 36) {
			level = 14;
		} else if (speed > 36 && speed <= 40) {
			level = 15;
		} else {
			level = 15;
		}
		return level;
	},
	/**生成随机字符串 */
	_makeid: function () {
		let text = "";
		let possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
		for (let i = 0; i < 5; i++) {
			text += possible.charAt(Math.floor(Math.random() * possible.length));
		}
		return text;
	},
	/**计算切片角点的坐标 */
	_getLonlat: function (x, y, cell, xAdd, yAdd) {
		let lon = (x + xAdd * cell) / Math.PI * 180; //第一个点 左上
		let lat = 180 / Math.PI * (2 * Math.atan(Math.exp(((y - yAdd * cell) / Math.PI * 180) * Math.PI / 180)) -
			Math.PI / 2);
		return {
			lon: lon,
			lat: lat
		}
	},
	/**uv计算角度和大小 */
	_computeUV: function (u_value, v_value) {
		let value = Math.sqrt(u_value * u_value + v_value * v_value);
		let angle = Math.acos(u_value / value);
		if (v_value < 0) {
			angle = -angle;
		}
		angle = Math.round(angle / Math.PI * 180.0 + 90);
		if (angle < 0) {
			angle = angle + 360;
		}
		angle = Math.round(360 - angle);
		return {
			value: value,
			angle: angle
		};
	},
	/**线性变化颜色带 */
	_setcolor: function (speed) {
		let minValue = 0, maxValue = 18;
		let col, r, g, b;
		let part = (maxValue - minValue) / 4.0;
		let colorRamp = 255.0 / part;
		if (speed < part + minValue) {
			col = speed - minValue;
			r = 0;
			g = Math.round(col * colorRamp);
			b = 255;
		} else if (speed >= part + minValue && speed < 2 * part + minValue) {
			col = speed - (part + minValue);
			r = 0;
			g = 255;
			b = Math.round(255 - col * colorRamp);
		} else if (speed >= 2 * part + minValue && speed < 3 * part + minValue) {
			col = speed - (2 * part + minValue);
			r = Math.round(col * colorRamp);
			g = 255;
			b = 0;
		} else if (speed >= 3 * part + minValue && speed < 4 * part + minValue) {
			col = speed - (3 * part + minValue);
			r = 255;
			g = Math.round(255 - col * colorRamp);
			b = 0;
		} else {
			r = 255;
			g = 0;
			b = 0;
		}
		return { r: r, g: g, b: b };
	},
	/**根据经纬度计算行列号 */
	_getRange: function (leftup, rightdown, zoom) {
		let leftuprowcol = this._getCornerNum(leftup.lat, leftup.lng, zoom);
		let rightdownrowcol = this._getCornerNum(rightdown.lat, rightdown.lng, zoom);
		return {
			left: leftuprowcol.colNum === 0 ? leftuprowcol.colNum : leftuprowcol.colNum - 1,
			up: leftuprowcol.rowNum === 0 ? leftuprowcol.rowNum : leftuprowcol.rowNum - 1,
			right: rightdownrowcol.colNum,
			down: rightdownrowcol.rowNum
		};
	},
	/**计算横轴墨卡托投影下的坐标 */
	_getCornerNum: function (lat, lon, level) {
		let d = Math.PI / 180;
		let x = lon * d;
		let y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);
		y = y * Math.PI / 180;
		//先转墨卡托，用墨卡托求行列号
		let rowNumber = (Math.PI - y) / (2 * Math.PI) * Math.pow(2, level);
		let colNumber = (x + Math.PI) / (2 * Math.PI) * Math.pow(2, level);
		return {
			rowNum: Math.round(rowNumber),
			colNum: Math.round(colNumber)
		};
	},
})

export default function (options) {
	return new L.WindFeatherLayer(options)
}